#! /bin/sh /usr/share/dpatch/dpatch-run
## 76_7759_repeat_pict.dpatch by  <root@mythserver.home.rodriguez-vudoyra.com>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: No description.

@DPATCH@
diff -urNad mythtv-0.22.0-fixes22952~/libs/libmythtv/NuppelVideoPlayer.cpp mythtv-0.22.0-fixes22952/libs/libmythtv/NuppelVideoPlayer.cpp
--- mythtv-0.22.0-fixes22952~/libs/libmythtv/NuppelVideoPlayer.cpp	2009-12-20 14:32:09.000000000 -0600
+++ mythtv-0.22.0-fixes22952/libs/libmythtv/NuppelVideoPlayer.cpp	2009-12-20 14:32:48.000000000 -0600
@@ -253,13 +253,14 @@
       lastsync(false),              m_playing_slower(false),
       m_stored_audio_stretchfactor(1.0),
       audio_paused(false),
+      repeat_delay(0),
       // Audio warping stuff
       usevideotimebase(false),
       warpfactor(1.0f),             warpfactor_avg(1.0f),
       warplbuff(NULL),              warprbuff(NULL),
       warpbuffsize(0),
       // Time Code stuff
-      prevtc(0),
+      prevtc(0),                    prevrp(0),
       tc_avcheck_framecounter(0),   tc_diff_estimate(0),
       savedAudioTimecodeOffset(0),
       // LiveTVChain stuff
@@ -2388,6 +2389,8 @@
 
     avsync_adjustment = 0;
 
+    repeat_delay = 0;
+
     if (usevideotimebase)
     {
         warpfactor_avg = gContext->GetNumSetting("WarpFactor", 0);
@@ -2470,8 +2473,10 @@
     if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
         ps = kScan_Progressive;
 
+    bool dropframe = false;
     if (diverge < -MAXDIVERGE)
     {
+        dropframe = true;
         // If video is way behind of audio, adjust for it...
         QString dbg = QString("Video is %1 frames behind audio (too slow), ")
             .arg(-diverge);
@@ -2505,7 +2510,7 @@
 
         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
                 .arg(avsync_adjustment).arg(m_double_framerate));
-        videosync->WaitForFrame(avsync_adjustment);
+        videosync->WaitForFrame(avsync_adjustment + repeat_delay);
         VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
         if (!resetvideo)
             videoOutput->Show(ps);
@@ -2557,6 +2562,12 @@
                 videoOutput->Show(ps);
             }
         }
+
+        repeat_delay = frame_interval * buffer->repeat_pict * 0.5;
+
+        if (repeat_delay)
+            VERBOSE(VB_TIMESTAMP, QString("A/V repeat_pict, adding %1 repeat "
+                    "delay").arg(repeat_delay));
     }
     else
     {
@@ -2571,7 +2582,8 @@
                 .arg(warpfactor).arg(warpfactor_avg));
     }
 
-    videosync->AdvanceTrigger();
+    if (!dropframe)
+        videosync->AdvanceTrigger();
     avsync_adjustment = 0;
 
     if (diverge > MAXDIVERGE)
@@ -2615,13 +2627,15 @@
 
             // If the timecode is off by a frame (dropped frame) wait to sync
             if (delta > (int) frame_interval / 1200 &&
-                delta < (int) frame_interval / 1000 * 3)
+                delta < (int) frame_interval / 1000 * 3 &&
+                prevrp == 0)
             {
                 //cerr << "+ ";
                 videosync->AdvanceTrigger();
                 if (m_double_framerate)
                     videosync->AdvanceTrigger();
             }
+            prevrp = buffer->repeat_pict;
 
             avsync_delay = (buffer->timecode - currentaudiotime) * 1000;//usec
             // prevents major jitter when pts resets during dvd title
diff -urNad mythtv-0.22.0-fixes22952~/libs/libmythtv/NuppelVideoPlayer.h mythtv-0.22.0-fixes22952/libs/libmythtv/NuppelVideoPlayer.h
--- mythtv-0.22.0-fixes22952~/libs/libmythtv/NuppelVideoPlayer.h	2009-12-20 14:32:09.000000000 -0600
+++ mythtv-0.22.0-fixes22952/libs/libmythtv/NuppelVideoPlayer.h	2009-12-20 14:32:48.000000000 -0600
@@ -804,6 +804,7 @@
     bool       decode_extra_audio;
     float      m_stored_audio_stretchfactor;
     bool       audio_paused;
+    int        repeat_delay;
 
     // Audio warping stuff
     bool       usevideotimebase;
@@ -815,6 +816,7 @@
  
     // Time Code stuff
     int        prevtc;        ///< 32 bit timecode if last VideoFrame shown
+    int        prevrp;        ///< repeat_pict of last frame
     int        tc_avcheck_framecounter;
     long long  tc_wrap[TCTYPESMAX];
     long long  tc_lastval[TCTYPESMAX];
diff -urNad mythtv-0.22.0-fixes22952~/libs/libmythtv/vsync.cpp mythtv-0.22.0-fixes22952/libs/libmythtv/vsync.cpp
--- mythtv-0.22.0-fixes22952~/libs/libmythtv/vsync.cpp	2009-10-14 20:32:47.000000000 -0500
+++ mythtv-0.22.0-fixes22952/libs/libmythtv/vsync.cpp	2009-12-20 14:32:48.000000000 -0600
@@ -187,11 +187,13 @@
 /** \fn VideoSync::CalcDelay()
  *  \brief Calculates the delay to the next frame.
  *
- *   Regardless of the timing method, if delay is greater than two full
+ *   Regardless of the timing method, if delay is greater than four full
  *   frames (could be greater than 20 or greater than 200), we don't want
  *   to freeze while waiting for a huge delay. Instead, contine playing 
  *   video at half speed and continue to read new audio and video frames
  *   from the file until the sync is 'in the ballpark'.
+ *   Also prevent the nexttrigger from falling too far in the past in case
+ *   we are trying to speed up video output faster than possible.
  */
 int VideoSync::CalcDelay()
 {
@@ -205,12 +207,22 @@
 
     //cout << "delay " << ret_val << endl;
 
-    if (ret_val > m_frame_interval * 2)
+    if (ret_val > m_frame_interval * 4)
     {
         if (m_interlaced)
-            ret_val = m_frame_interval; // same as / 2 * 2.
+            ret_val = (m_frame_interval / 2) * 4;
         else
-            ret_val = m_frame_interval * 2;
+            ret_val = m_frame_interval * 4;
+
+        // set nexttrigger to our new target time
+        m_nexttrigger.tv_sec = now.tv_sec;
+        m_nexttrigger.tv_usec = now.tv_usec;
+        OffsetTimeval(m_nexttrigger, ret_val);
+    }
+
+    if (ret_val < -m_frame_interval)
+    {
+        ret_val = -m_frame_interval;
 
         // set nexttrigger to our new target time
         m_nexttrigger.tv_sec = now.tv_sec;
@@ -681,6 +693,7 @@
         // If late, draw the frame ASAP.  If early, hold the CPU until
         // half as late as the previous frame (fudge).
         m_delay = CalcDelay();
+        m_fudge = min(m_fudge, m_frame_interval);
         while (m_delay + m_fudge > 0)
         {
             m_delay = CalcDelay();
